package com.jprocms.module.cms.convert.content;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.jpro.framework.common.pojo.PageResult;
import com.jpro.framework.common.util.string.StrUtils;
import com.jprocms.module.cms.controller.admin.content.dto.ContentAutoPushDto;
import com.jprocms.module.cms.controller.admin.content.vo.*;
import com.jprocms.module.cms.dal.dataobject.content.ContentCountDO;
import com.jprocms.module.cms.dal.dataobject.content.ContentDO;
import com.jprocms.module.cms.dal.dataobject.content.ContentExtDO;
import com.jprocms.module.cms.enums.EnumTimeStage;
import com.jprocms.module.cms.es.dto.ContentEsDto;
import com.jprocms.module.cms.es.dto.EsFrontSearchDto;
import com.jprocms.module.cms.es.dto.FrontSearchDto;
import com.jprocms.module.cms.es.vo.EsContentVO;
import com.jprocms.module.cms.query.WhereCondition;
import com.jprocms.module.cms.util.RequestUtils;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.IterableMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;

import javax.servlet.http.HttpServletRequest;
import java.time.*;
import java.util.*;

import static com.jpro.framework.security.core.util.SecurityFrameworkUtils.AUTHORIZATION_BEARER;
import static com.jprocms.module.cms.constant.CmsSysConstants.HEAD_AUTHORIZATION;
import static org.apache.commons.lang3.StringUtils.EMPTY;

/**
 * 内容 Convert
 *
 * @author jprocms
 */
@Mapper
public interface ContentConvert {

    ContentConvert INSTANCE = Mappers.getMapper(ContentConvert.class);

    @Mapping(source = "releaseTime", target = "releaseTime", qualifiedByName = "customTimeMapping")
    ContentDO convert(ContentCreateReqVO bean);

    @Mapping(source = "releaseTime", target = "releaseTime", qualifiedByName = "customTimeMapping")
    ContentDO convert(ContentUpdateReqVO bean);

    @Mapping(source = "releaseTime", target = "releaseTime", qualifiedByName = "customTimeToOffsetTimeMapping")
    ContentUpdateReqVO convertToUpdateReqVO(ContentDO bean);

    @Named("customTimeMapping")
    default OffsetDateTime customTimeMapping(Date dateTime) {
        return dateTime != null ? OffsetDateTime.ofInstant(dateTime.toInstant(), ZoneOffset.UTC) : null;
    }

    @Named("dataTimeToLocalMapping")
    default LocalDateTime dataTimeToLocalMapping(Date dateTime) {
        if (dateTime == null) {
            return null;
        }
        // 将java.util.Date转换为java.time.Instant对象
        Instant instant = dateTime.toInstant();
        // 通过Instant对象获取ZoneId，默认是系统的默认ZoneId
        ZoneId zoneId = ZoneId.systemDefault();
        // 使用Instant和ZoneId将Date转换为LocalDateTime
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
        return localDateTime;
    }

    @Named("localToDataMapping")
    default Date localToDataMapping(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    @Named("customTimeToOffsetTimeMapping")
    default Date customTimeToOffsetTimeMapping(OffsetDateTime dateTime) {
        return dateTime != null ? Date.from(dateTime.toInstant()) : null;
    }

    @Named("customTimeToOffsetTimeMapping2")
    default Date customTimeToOffsetTimeMapping2(OffsetDateTime dateTime) {
        return dateTime != null ? DateUtil.date(dateTime.toInstant().toEpochMilli()) : null;
    }

    @Mapping(source = "releaseTime", target = "releaseTime", qualifiedByName = "customTimeToOffsetTimeMapping")
    ContentRespVO convert(ContentDO bean);

    @Mapping(source = "releaseTime", target = "releaseTime", qualifiedByName = "customTimeToOffsetTimeMapping")
    ContentBaseVO convertForBaseVO(ContentDO bean);

    @Mapping(source = "contentDO.id", target = "id")
    @Mapping(source = "contentDO.createTime", target = "createTime")
    @Mapping(source = "ext.images", target = "images")
    @Mapping(source = "ext.attachs", target = "attachs")
    @Mapping(source = "ext.subtitle", target = "subtitle")
    @Mapping(source = "ext.keywords", target = "keywords")
    @Mapping(source = "ext.description", target = "description")
    @Mapping(source = "ext.author", target = "author")
    @Mapping(source = "ext.source", target = "source")
    @Mapping(source = "ext.sysImage", target = "sysImage")
    @Mapping(source = "ext.sysVideo", target = "sysVideo")
    @Mapping(source = "ext.sysAudio", target = "sysAudio")
    @Mapping(source = "ext.sysAttach", target = "sysAttach")
    @Mapping(source = "ext.sysAttachName", target = "sysAttachName")
    @Mapping(source = "ext.targetBlank", target = "targetBlank")
    @Mapping(source = "ext.text", target = "text")
    @Mapping(source = "contentDO.releaseTime", target = "releaseTime", qualifiedByName = "customTimeToOffsetTimeMapping")
    @Mapping(source = "ext.docPdf", target = "docPdf")
    @Mapping(source = "ext.docName", target = "docName")
    @Mapping(source = "ext.originDoc", target = "originDoc")
    @Mapping(source = "ext.onlineTime", target = "onlineTime")
    @Mapping(source = "ext.rejectReason", target = "rejectReason")
    @Mapping(source = "ext.processInstanceId", target = "processInstanceId")
    @Mapping(source = "ext.pcTpl", target = "pcTpl")
    @Mapping(source = "ext.h5Tpl", target = "h5Tpl")
    @Mapping(source = "ext.topStartTime", target = "topStartTime")
    @Mapping(source = "ext.offlineTime", target = "offlineTime")
    @Mapping(source = "ext.topEndTime", target = "topEndTime")
    @Mapping(source = "ext.outLink", target = "outLink")
    @Mapping(source = "ext.sysVideoDuration", target = "sysVideoDuration")
    @Mapping(source = "ext.editorType", target = "editorType")
    ContentRespVO convert(ContentDO contentDO, ContentExtDO ext);

    @Mapping(source = "contentDO.id", target = "id")
    @Mapping(source = "contentDO.createTime", target = "createTime")
    @Mapping(source = "ext.images", target = "images")
    @Mapping(source = "ext.attachs", target = "attachs")
    @Mapping(source = "ext.subtitle", target = "subtitle")
    @Mapping(source = "ext.keywords", target = "keywords")
    @Mapping(source = "ext.description", target = "description")
    @Mapping(source = "ext.author", target = "author")
    @Mapping(source = "ext.source", target = "source")
    @Mapping(source = "ext.sysImage", target = "sysImage")
    @Mapping(source = "ext.sysVideo", target = "sysVideo")
    @Mapping(source = "ext.sysAudio", target = "sysAudio")
    @Mapping(source = "ext.sysAttach", target = "sysAttach")
    @Mapping(source = "ext.sysAttachName", target = "sysAttachName")
    @Mapping(source = "ext.targetBlank", target = "targetBlank")
    @Mapping(source = "ext.text", target = "text")
    @Mapping(source = "ext.docPdf", target = "docPdf")
    @Mapping(source = "ext.docName", target = "docName")
    @Mapping(source = "ext.originDoc", target = "originDoc")
    @Mapping(source = "ext.onlineTime", target = "onlineTime")
    @Mapping(source = "ext.rejectReason", target = "rejectReason")
    @Mapping(source = "ext.processInstanceId", target = "processInstanceId")
    @Mapping(source = "ext.pcTpl", target = "pcTpl")
    @Mapping(source = "ext.h5Tpl", target = "h5Tpl")
    @Mapping(source = "ext.topStartTime", target = "topStartTime")
    @Mapping(source = "ext.offlineTime", target = "offlineTime")
    @Mapping(source = "ext.topEndTime", target = "topEndTime")
    @Mapping(source = "ext.outLink", target = "outLink")
    @Mapping(source = "ext.sysVideoDuration", target = "sysVideoDuration")
    @Mapping(source = "ext.editorType", target = "editorType")
    @Mapping(source = "contentDO.releaseTime", target = "releaseTime", ignore = true)
    ContentTopViewRespVO convertTopViewResp(ContentDO contentDO, ContentExtDO ext);


    @Mapping(source = "bean.channel.nodeList", target = "nodeList")
    ContentOriginVo convertForOrigin(ContentDO bean);

    @Named(value = "convertMore")
    default ContentRespVO convertMore(ContentDO bean) {
        ContentRespVO respVO = convert(bean, bean.getExt());
        respVO.setEditable(bean.getEditable());
        respVO.setCustoms(bean.getCustoms());
        respVO.setTagNames(bean.getTagNames());
        respVO.setChannelName(bean.getChannelName());
        respVO.setEditPublishContentToSubmit(bean.getSite().getSiteConfig().getBase().getEditPublishContentToSubmit());
        //后台url 发布状态就是url，其他状态则读取预览url
        final HttpServletRequest httpServletRequest = RequestUtils.getHttpServletRequest();
        String authorization = EMPTY;
        if (httpServletRequest != null) {
            //将授权header拼接到url
            authorization = httpServletRequest.getHeader(HEAD_AUTHORIZATION);
            if(StringUtils.isNotBlank(authorization)){
                int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
                if (index == -1) { // 未找到
                    return null;
                }
                authorization = authorization.substring(index + 7).trim();
            }
        }
        if (bean.isPublish()) {
            respVO.setUrl(bean.getUrl());
        } else {
            respVO.setUrl(bean.getPreviewUrl(authorization));
        }
        respVO.setLivePreviewUrl(bean.getLivePreviewUrl(authorization));
        if (bean.getReleaseTime() != null) {
            respVO.setReleaseTime(Date.from(bean.getReleaseTime().toInstant()));
        }
        if (bean.getOriginContentId() != null) {
            respVO.setOriginContent(convertForOrigin(bean.getOriginContent()));
        }
        respVO.setProcessDefinitionId(bean.getChannel().getProcessDefinitionId());
        return respVO;
    }


    @IterableMapping(qualifiedByName = "convertMore")
    List<ContentRespVO> convertList(List<ContentDO> page);

    @IterableMapping(qualifiedByName = "convertMore")
    PageResult<ContentRespVO> convertPage(PageResult<ContentDO> page);

    @Named(value = "convertContentTopViewResp")
    default ContentTopViewRespVO convertToTopViewResp(ContentDO bean) {
        ContentTopViewRespVO respVO = convertTopViewResp(bean, bean.getExt());
        respVO.setCustoms(bean.getCustoms());
        respVO.setTagNames(bean.getTagNames());
        respVO.setChannelName(bean.getChannelName());
        if (bean.isPublish()) {
            respVO.setUrl(bean.getUrl());
        }
        if (bean.getReleaseTime() != null) {
            respVO.setReleaseTime(Date.from(bean.getReleaseTime().toInstant()));
        }
        //后台url 发布状态就是url，其他状态则读取预览url
        final HttpServletRequest httpServletRequest = RequestUtils.getHttpServletRequest();
        String authorization = EMPTY;
        if (httpServletRequest != null) {
            //将授权header拼接到url
            authorization = httpServletRequest.getHeader(HEAD_AUTHORIZATION);
            int index = authorization.indexOf(AUTHORIZATION_BEARER + " ");
            if (index == -1) { // 未找到
                return respVO;
            }
            authorization = authorization.substring(index + 7).trim();
        }
        if (!bean.isPublish()) {
            respVO.setUrl(bean.getPreviewUrl(authorization));
        }
        return respVO;
    }

    @Named(value = "esToContent")
    @Mapping(source = "releaseTime", target = "releaseTime", qualifiedByName = "customTimeMapping")
    @Mapping(source = "createTime", target = "createTime", qualifiedByName = "dataTimeToLocalMapping")
    ContentDO convertEsToContent(EsContentVO esContentVO);

    @IterableMapping(qualifiedByName = "esToContent")
    List<ContentDO> convertEsToContentList(List<EsContentVO> page);

    @IterableMapping(qualifiedByName = "esToContent")
    PageResult<ContentDO> convertEsToContentPage(PageResult<EsContentVO> page);

    ContentCopyVo convertPushToCopyVo(ContentPushVo bean);

    ContentCopyVo convertPushToCopyVo(ContentAutoPushDto bean);

    default ContentCopyVo convertPushDefToCopyVo(ContentAutoPushDto bean) {
        ContentCopyVo vo = convertPushToCopyVo(bean);
        vo.setIds(Arrays.asList(bean.getId()));
        return vo;
    }

    @Mapping(target = "id", source = "contentDO.id")
    @Mapping(target = "createTime", source = "contentDO.createTime", qualifiedByName = "localToDataMapping")
    @Mapping(target = "creator", source = "contentDO.creator")
    @Mapping(target = "customs", source = "contentDO.customsWithoutEditor")
    @Mapping(source = "extDO.subtitle", target = "subtitle")
    @Mapping(source = "extDO.keywords", target = "keywords")
    @Mapping(source = "extDO.description", target = "description")
    @Mapping(source = "extDO.author", target = "author")
    @Mapping(source = "extDO.source", target = "source")
    @Mapping(source = "extDO.sysImage", target = "sysImage")
    @Mapping(source = "extDO.sysVideo", target = "sysVideo")
    @Mapping(source = "extDO.sysAudio", target = "sysAudio")
    @Mapping(source = "extDO.sysAttach", target = "sysAttach")
    @Mapping(source = "extDO.sysAttachName", target = "sysAttachName")
    @Mapping(source = "contentDO.ups", target = "ups")
    @Mapping(source = "contentDO.downs", target = "downs")
    @Mapping(source = "contentDO.comments", target = "comments")
    @Mapping(source = "contentDO.views", target = "views")
    @Mapping(source = "contentDO.downloads", target = "downloads")
    @Mapping(source = "contentDO.favorites", target = "favorites")
    @Mapping(source = "contentDO.docPdf", target = "docPdf")
    @Mapping(source = "contentDO.docName", target = "docName")
    @Mapping(source = "contentDO.originDoc", target = "originDoc")
    ContentEsDto convertToEsDtoSimple(ContentDO contentDO, ContentExtDO extDO, ContentCountDO contentCountDO);

//    @Mapping(source = "releaseTimeStart", target = "releaseTimeStart", qualifiedByName = "customTimeToOffsetTimeMapping")
//    @Mapping(source = "releaseTimeEnd", target = "releaseTimeEnd", qualifiedByName = "customTimeToOffsetTimeMapping")
EsFrontSearchDto convert2EsQuertDtoDef(ContentFrontQueryReqVO queryDto);

    default EsFrontSearchDto convert2EsQuertDto(ContentFrontQueryReqVO queryDto) {
        EsFrontSearchDto esFrontSearchDto = convert2EsQuertDtoDef(queryDto);
        if (CollUtil.isEmpty(queryDto.getCustomsConditions())) {
            return esFrontSearchDto;
        }
        Map<String, Object> customFields = new HashMap();
        for (WhereCondition customsCondition : queryDto.getCustomsConditions()) {
            //将自定义字段的特征结尾给截取掉
            String key = customsCondition.getColumn();
            customFields.put(key, customsCondition.getValue());
        }
        esFrontSearchDto.setCustoms(customFields);
        return esFrontSearchDto;
    }

    EsFrontSearchDto convert2EsQuertDtoDef(FrontSearchDto queryDto);

    default EsFrontSearchDto convert2EsQuertDto(FrontSearchDto queryDto) {
        EsFrontSearchDto dto = convert2EsQuertDtoDef(queryDto);
        if (dto == null) {
            return dto;
        }
        dto.setKeyWords(StrUtils.splitToString(queryDto.getQ()));
        dto.setChannelIds(StrUtils.splitToLong(queryDto.getChannelIdStrs()));
        dto.setDictBlocks(StrUtils.splitToLong(queryDto.getDictBlockStrs()));
        Integer timeStage = queryDto.getTimeStage();
        EnumTimeStage stage = EnumTimeStage.getTimeStage(timeStage);
        DateTime now = DateTime.now();
        dto.setReleaseTimeEnd(now.toJdkDate());
        dto.setSiteId(queryDto.getSiteId());
        switch (stage) {
            case day:
                dto.setReleaseTimeStart(DateUtil.beginOfDay(now).toJdkDate());
                break;
            case week:
                dto.setReleaseTimeStart(DateUtil.beginOfWeek(now).toJdkDate());
                break;
            case month:
                dto.setReleaseTimeStart(DateUtil.beginOfMonth(now).toJdkDate());
                break;
            case year:
                dto.setReleaseTimeStart(DateUtil.beginOfYear(now).toJdkDate());
                break;
            default:
        }
        return dto;
    }

}
